home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
program
/
cpp112.zoo
/
src
/
token.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-07-07
|
18KB
|
794 lines
/*---------------------------------------------------------------------*\
| |
| CPP -- a stand-alone C preprocessor |
| Copyright (c) 1993 Hacker Ltd. Author: Scott Bigham |
| |
| Permission is granted to anyone to use this software for any purpose |
| on any computer system, and to redistribute it freely, with the |
| following restrictions: |
| - No charge may be made other than reasonable charges for repro- |
| duction. |
| - Modified versions must be clearly marked as such. |
| - The author is not responsible for any harmful consequences of |
| using this software, even if they result from defects therein. |
| |
| token.c -- transform raw input to preprocessor tokens |
\*---------------------------------------------------------------------*/
/*
There are (for better or worse) three interfaces to the tokenizing
mechanism, at increasing levels of abstraction. _one_token() tokenizes
directly out of the input line buffer, and should generally only be used
while handling preprocessor directive lines. token() pre-tokenizes an
entire line of input at a time and doles it out one token at a time. Note
that tokens returned by token() may or may not have undergone macro
expansion; use it when you need access to pre-expanded input tokens.
exp_token() fully expands each token before returning it; this is usually
the best way to access input.
*/
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include "global.h"
#include "ztype.h"
#include "alloc.h"
#define BASE10 1
#define BASE8 2
#define BASE16 3
#define GRANULARITY 256
extern char *next_c;
static int tok_flags = 0;
static TokenP pushback_list;
/* mk_Token() -- allocate and initialize space for a Token */
TokenP mk_Token()
{
register TokenP T = alloc_Token();
T->val = T->hashval = T->flags = T->type = T->subtype = 0;
T->_txt.out_of_line = T->_ws.out_of_line = NULL;
T->flags |= (INLINE_TXT | INLINE_WS);
T->_txt.inline[0] = T->_ws.inline[0] = '\0';
T->next = NULL;
return T;
}
/* clear_txt() -- clear the text space of a token */
void clear_txt(T)
register TokenP T;
{
if (!(T->flags & INLINE_TXT) && T->_txt.out_of_line)
free(T->_txt.out_of_line);
T->flags |= INLINE_TXT;
T->_txt.inline[0] = '\0';
}
/* clear_ws() -- clear the white space of a token */
void clear_ws(T)
register TokenP T;
{
if (!(T->flags & INLINE_WS) && T->_ws.out_of_line)
free(T->_ws.out_of_line);
T->flags |= INLINE_WS;
T->_ws.inline[0] = '\0';
}
/* set_txt() -- set the text of a token to |s|, copying if necessary,
and deleting the current text, if any */
void set_txt(T, s)
register TokenP T;
register char *s;
{
if (!(T->flags & INLINE_TXT) && T->_txt.out_of_line)
free(T->_txt.out_of_line);
if (strlen(s) <= 7) {
T->flags |= INLINE_TXT;
strcpy(T->_txt.inline, s);
} else {
T->flags &= ~INLINE_TXT;
T->_txt.out_of_line = strdup(s);
}
}
/* set_txt_n() -- set the text of a token to the first |n| characters
of |s|, copying if necessary, and deleting the current text, if any */
void set_txt_n(T, s, n)
register TokenP T;
register char *s;
int n;
{
if (!(T->flags & INLINE_TXT) && T->_txt.out_of_line)
free(T->_txt.out_of_line);
if (n <= 7) {
T->flags |= INLINE_TXT;
strncpy(T->_txt.inline, s, n);
T->_txt.inline[n] = '\0';
} else {
T->flags &= ~INLINE_TXT;
T->_txt.out_of_line = mallok(n + 1);
strncpy(T->_txt.out_of_line, s, n);
T->_txt.out_of_line[n] = '\0';
}
}
/* set_ws() -- set the white space of a token to |s|, copying if
necessary, and deleting the current white space, if any */
void set_ws(T, s)
register TokenP T;
register char *s;
{
if (!(T->flags & INLINE_WS) && T->_ws.out_of_line)
free(T->_ws.out_of_line);
if (strlen(s) <= 3) {
T->flags |= INLINE_WS;
strcpy(T->_ws.inline, s);
} else {
T->flags &= ~INLINE_WS;
T->_ws.out_of_line = strdup(s);
}
}
/* free_token() -- return an allocated Token to the free list */
void free_token(T)
register TokenP T;
{
T->next = NULL;
free_tlist(T);
}
/* free_tlist() -- return a list of Token's to the free list */
void free_tlist(T)
register TokenP T;
{
register TokenP T1;
for (T1 = T; T; T = T1) {
T1 = T->next;
clear_txt(T);
clear_ws(T);
#if 0
T->next = next_free_tok;
next_free_tok = T;
#else
dealloc_Token(T);
#endif
}
}
/*
copy_token() -- return a new Token that is a duplicate of the given token
*/
TokenP copy_token(T1)
register TokenP T1;
{
register TokenP T2 = mk_Token();
*T2 = *T1;
if (!(T1->flags & INLINE_WS))
T2->_ws.out_of_line = strdup(T1->_ws.out_of_line);
if (!(T1->flags & INLINE_TXT))
T2->_txt.out_of_line = strdup(T1->_txt.out_of_line);
T2->next = NULL;
return T2;
}
/* copy_tlist() -- create a duplicate of a list of Token's */
TokenP copy_tlist(T1)
register TokenP T1;
{
Token head;
register TokenP T2 = &head;
for (T2->next = NULL; T1; T1 = T1->next, T2 = T2->next)
T2->next = copy_token(T1);
return head.next;
}
/* tok_shutdown() -- free all space allocated for Token's */
void tok_shutdown()
{
#ifdef DEBUG /* explicitly clean up, to check for memory leaks */
#if 0
register TokenP T, T1;
register int i;
for (T1 = T = tok_blocks; T; T = T1) {
T1 = T->next;
for (i = 1; i < GRANULARITY; i++) {
if (T[i].flags & IN_USE) {
fprintf(stderr, "@@@ Token not freed: ");
dump_token(&T[i]);
fputc('\n', stderr);
}
clear_txt(&T[i]);
clear_ws(&T[i]);
}
free(T);
}
fprintf(stderr, "%d total blocks allocated\n", num_blocks);
#else /* 0 */
cleanup_Token();
#endif /* 0 */
#endif
}
/*
push_tlist() -- "un-read" the list of Token's |T|; token() will return all
of these tokens in order before reading another token from the input file
*/
void push_tlist(T)
register TokenP T;
{
register TokenP t;
if (!T)
return;
t = T;
while (t->next)
t = t->next;
t->next = pushback_list;
pushback_list = T;
}
/* mk_eof() -- makes and returns an EOF_ token */
static TokenP mk_eof()
{
register TokenP T = mk_Token();
T->type = EOF_;
T->flags |= INLINE_TXT | INLINE_WS;
T->_ws.inline[0] = T->_txt.inline[0] = '\0';
return T;
}
/*
mk_stopper() -- makes and returns a STOP token. See expand_tlist() for
further information.
*/
TokenP mk_stopper()
{
register TokenP T = mk_Token();
T->type = STOP;
T->flags |= INLINE_TXT | INLINE_WS;
T->_ws.inline[0] = T->_txt.inline[0] = '\0';
return T;
}
/*
mk_unmarker() -- makes and returns a special token that informs the
tokenizer to unmark the macro text associated with token |T|. See
expand() for further information.
*/
TokenP mk_unmarker(T)
register TokenP T;
{
register TokenP T1 = copy_token(T);
T1->type = UNMARK;
T->flags |= INLINE_TXT | INLINE_WS;
T->_ws.inline[0] = T->_txt.inline[0] = '\0';
return T1;
}
/*
mk_printable() -- makes and returns an untyped token with an
arbitrary text body, for purposes of printing directly via
print_token().
*/
TokenP mk_printable(s)
const char *s;
{
register TokenP T = mk_Token();
T->type = DONT_CARE;
set_ws(T, " ");
set_txt(T, s);
return T;
}
/* flush_tokenizer() -- discard all Tokens pushed back by push_tlist() */
void flush_tokenizer()
{
free_tlist(pushback_list);
pushback_list = NULL;
}
/*
number() -- copies from |s| into the token |T| a string of characters
denoting an integer or floating-point constant. Returns a pointer to the
first uncopied character.
*/
static char *number(s, T)
register char *s;
register TokenP T;
{
int numtype = BASE10, fpflag = 0;
char *t;
T->type = NUMBER;
if (*s == '0') {
/* check for octal or hexadecimal constant */
if ((s[1] == 'x' || s[1] == 'X') && isxdigit(s[2])) {